package org.jheuristics.ga.operators.selectors;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.jheuristics.Individual;
import org.jheuristics.ga.DefaultPopulation;
import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.Population;
import org.jheuristics.ga.multiObjective.MultiObjectiveFitness;
import org.jheuristics.ga.operators.Selector;
import org.jheuristics.ga.transformations.FitnessToDoubleTransformation;

/**
 * TODO
 *
 * @author Marcell Manfrin, marcell@ourgrid.org, Oct 31, 2005
 */
public class BestMultiObjetiveFitnessSelector implements Selector {
    private FitnessToDoubleTransformation[] transformations;

	/**
	 * TODO
	 *
	 * @param transformation
	 */
	public BestMultiObjetiveFitnessSelector(FitnessToDoubleTransformation[] transformation) {
		setTransformations(transformation);
	}

	/**
	 * TODO
	 *
	 * @param population
	 * @param howMany
	 * @param status
	 * @param config
	 * @return
	 * @see org.jheuristics.ga.operators.Selector#select(org.jheuristics.ga.Population, int, org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	public Individual[] select(Population population, int howMany, GAStatus status, GAConfig config) {
        if (null == population) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
        if (0 == population.size()) {
        	return new Individual[0];
        }
		Comparable[] fitness = ((MultiObjectiveFitness) population.getIndividual(0).getFitness()).getObjectives();
		if (fitness.length != transformations.length) {
			// TODO: ERROR MSG
			throw new IllegalStateException();
		}
		double min[] = new double[fitness.length];
		int index[] = new int[fitness.length];
		int count = 0;
		for (int i = 0; i < fitness.length; i++) {
			double value = getTransformations()[i].toDouble(fitness[i]);
			min[i] = value;
			index[i] = count;
		}

		for (Iterator it = population.iterator(); it.hasNext(); count++) {
			fitness = ((MultiObjectiveFitness) ((Individual) it.next()).getFitness()).getObjectives();
			if (fitness.length != transformations.length) {
				// TODO: ERROR MSG
				throw new IllegalStateException();
			}
			for (int i = 0; i < fitness.length; i++) {
				double value = getTransformations()[i].toDouble(fitness[i]);
				if (value < min[i]) {
					min[i] = value;
					index[i] = count;
				}
			}
		}

		Set indexes = new HashSet();
		for (int i = 0; i < index.length; i++) {
			indexes.add(new Integer(index[i]));
		}
		Population result = new DefaultPopulation();
		for (Iterator it = indexes.iterator(); it.hasNext(); ) {
			result.addIndividual(population.getIndividual(((Integer) it.next()).intValue()));
		}
		return result.toIndividualArray();
	}


	/**
	 * TODO
	 *
	 * @return
	 */
	public FitnessToDoubleTransformation[] getTransformations() {
		return transformations;
	}


	/**
	 * TODO
	 *
	 * @param transformation
	 */
	public void setTransformations(FitnessToDoubleTransformation[] transformation) {
		if (null == transformation) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
		for (int i = 0; i < transformation.length; i++) {
			if (null == transformation[i]) {
				// TODO: ERROR MSG
				throw new NullPointerException();
			}
		}
		this.transformations = transformation;
	}

}
